package com.hzhq.contract.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hzhq.contract.bean.dto.AttachmentDTO;
import com.hzhq.contract.bean.dto.ContractDTO;
import com.hzhq.contract.bean.dto.ContractStatusDTO;
import com.hzhq.contract.bean.entity.*;
import com.hzhq.contract.bean.vo.ContractVO;
import com.hzhq.contract.convert.ContractConvertBasic;
import com.hzhq.contract.convert.ContractTypeConvertBasic;
import com.hzhq.contract.convert.DepartConvertBasic;
import com.hzhq.contract.convert.UserConvertBasic;
import com.hzhq.contract.result.Result;
import com.hzhq.contract.service.*;
import com.hzhq.contract.status.DefaultValue;
import com.hzhq.contract.util.EncryptUtil;
import com.hzhq.contract.util.Page2ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.Binary;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: hzhq1255
 * @mail: hzhq1255@163.com
 * @date: 2021/4/13 18:15
 * @desc:
 */
@Slf4j
@Api(tags = "合同管理")
@CrossOrigin
@RestController
@ResponseBody
@RequestMapping("/api/v1/contracts")
public class ContractController {

    @Autowired
    ContractTypeService typeService;

    @Autowired
    ContractService contractService;

    @Autowired
    AttachmentService attachmentService;

    @Autowired
    TemplateService templateService;

    @Autowired
    ContractStatusService statusService;

    @Autowired
    UserService userService;

    @Autowired
    DepartService departService;

    @Autowired
    MongoTemplate mongoTemplate;


    @ApiOperation("getAllContractPage")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "currentPage", value = "当前页", example = "1", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "pageSize", value = "个数", example = "10", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer")
    })
    @ResponseBody
    @RequestMapping(value = "/currentPage/{currentPage}/pageSize/{pageSize}", method = RequestMethod.GET)
    private Result<Object> getAllContractPage(@PathVariable("currentPage") @NotNull Integer currentPage,
                                              @PathVariable("pageSize") @NotNull Integer pageSize,
                                              @RequestParam(value = "loginUser", required = false) String loginUser,
                                              @RequestParam(value = "departName", required = false) String departName,
                                              @RequestParam(value = "typeName", required = false) String typeName,
                                              @RequestParam(value = "createUser", required = false) String createUser,
                                              @RequestParam(value = "approvalPerson", required = false) String approvalPerson,
                                              @RequestParam(value = "contactName", required = false) String contractName,
                                              @RequestParam(value = "passed", required = false) Integer passed,
                                              @RequestParam(value = "edited", required = false) Integer edited) {
        if (loginUser != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByUserDepart(loginUser, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (departName != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByDepart(departName, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (typeName != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByType(typeName, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (createUser != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByCreateUser(createUser, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (approvalPerson != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByApprovalPerson(approvalPerson, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (contractName != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.searchByName(contractName, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (passed != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByPassed(passed, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        if (edited != null) {
            return Result.success(Page2ResultUtil.getPageData(
                    contractService.getAllPageByEdited(edited, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));
        }
        return Result.success(Page2ResultUtil.getPageData(contractService.getAllPage(currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));


    }


    @ApiOperation("getAllContractPage")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "currentPage", value = "当前页", example = "1", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "pageSize", value = "个数", example = "10", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer")
    })
    @ResponseBody
    @RequestMapping(value = "/dynamic/currentPage/{currentPage}/pageSize/{pageSize}", method = RequestMethod.GET)
    private Result<Object> getAllPage(@PathVariable("currentPage") @NotNull Integer currentPage,
                                      @PathVariable("pageSize") @NotNull Integer pageSize,
                                      @RequestParam(value = "contractName", required = false) String contractName,
                                      @RequestParam(value = "templateName",required = false) String templateName,
                                      @RequestParam(value = "departName", required = false) String departName,
                                      @RequestParam(value = "typeName", required = false) String typeName,
                                      @RequestParam(value = "createUser", required = false) String createUser,
                                      @RequestParam(value = "approvalPerson", required = false) String approvalPerson,
                                      @RequestParam(value = "editedUser",required = false) String editedUser,
                                      @RequestParam(value = "contactPerson", required = false) String contactPerson,
                                      @RequestParam(value = "passed", required = false) Integer passed,
                                      @RequestParam(value = "edited", required = false) Integer edited,
                                      @RequestParam(value = "completed", required = false) Integer completed) {
        ContractDTO contractDTO = new ContractDTO();
        if (null != createUser && !"".equals(createUser)) {
            contractDTO.setCreateUser(UserConvertBasic.INSTANCE.dtoToPo(userService.getOneByName(createUser)));
        }
        if (null != departName && !"".equals(departName)) {
            contractDTO.setDepart(DepartConvertBasic.INSTANCE.dtoToPo(departService.getOneByDepartName(departName)));
        }
        if (null != typeName && !"".equals(typeName)) {
            contractDTO.setContractType(ContractTypeConvertBasic.INSTANCE.dtoToPo(typeService.getOneByName(typeName)));
        }
        if (null != approvalPerson && !"".equals(approvalPerson)) {
            contractDTO.setApprovalPerson(approvalPerson);
        }
        if( null != editedUser && !"".equals(editedUser)){
            contractDTO.setLastEditedUser(editedUser);
        }
        if(null != templateName && !"".equals(templateName)){
            contractDTO.setTemplateName(templateName);
        }

        contractDTO.setContractName(contractName);
        contractDTO.setContactPerson(contactPerson);
        contractDTO.setPassed(passed);
        contractDTO.setEdited(edited);
        contractDTO.setCompleted(completed);
        contractDTO.setDeleted(DefaultValue.NOT_DELETED);
        return Result.successWithData(Page2ResultUtil.getPageData(contractService.getAllPage(contractDTO, currentPage, pageSize).map(ContractConvertBasic.INSTANCE::dtoToVo)));

    }

    @ApiOperation("getContractById")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", paramType = "path", dataType = "String", dataTypeClass = String.class)
    })
    @ResponseBody
    @RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
    private Result<Object> getContractById(@PathVariable("id") @NotNull String id) {
        if (!ObjectId.isValid(id)) {
            return Result.errorWithMsg("id=" + id + " is not valid!");
        }
        ContractVO contractVO = ContractConvertBasic.INSTANCE.dtoToVo(contractService.getOneById(id));
        if (contractVO == null) {
            return Result.errorWithMsg("id=" + id + " is not existed!");
        }
        return Result.successWithData(contractVO);
    }

    @ApiOperation("getContractByName")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "name", paramType = "path", dataType = "String", dataTypeClass = String.class)
    })
    @ResponseBody
    @RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
    private Result<Object> getContractByName(@PathVariable("name") @NotNull String name) {
        ContractVO contractVO = ContractConvertBasic.INSTANCE.dtoToVo(contractService.getOneByName(name));
        if (contractVO == null) {
            return Result.errorWithMsg("typeName=" + name + " is not existed!");
        }
        return Result.successWithData(contractVO);
    }

    @ApiOperation("deleteContractById")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", paramType = "path", dataType = "String", dataTypeClass = String.class)
    })
    @ResponseBody
    @RequestMapping(value = "/delete/id/{id}", method = RequestMethod.POST)
    private Result<Object> deleteContractById(@PathVariable("id") @NotNull String id) {
        if (!ObjectId.isValid(id)) {
            return Result.errorWithMsg("id=" + id + " is not valid!");
        }
        String deleteId = contractService.deleteById(new ObjectId(id));
        if (deleteId == null) {
            return Result.errorWithMsg("typeId=" + id + " is not existed!");
        }
        return Result.successWithData(deleteId);
    }

    private List<AttachmentDTO> fileConvertToAttachmentDto(String contractId, List<MultipartFile> files) {
        List<AttachmentDTO> attachmentList = new ArrayList<>();
        for (MultipartFile file : files) {
            AttachmentDTO attachment;
            try {
                String md5 = EncryptUtil.getMd5File(file.getInputStream());
                attachment = AttachmentDTO.builder()
                        .attachName(file.getOriginalFilename())
                        .contractId(contractId)
                        .contentType(file.getContentType())
                        .size(file.getSize())
                        .content(new Binary(file.getBytes()))
                        .md5(md5)
                        .path("/contract/" + contractId + "/attachment/" + md5)
                        .uploadTime(new Date())
                        .deleted(DefaultValue.NOT_DELETED)
                        .build();
                attachmentList.add(attachment);
            } catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
        }
        return attachmentList;
    }


    @ApiOperation("deleteContractById")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contract", value = "contract", paramType = "form", dataType = "Object", dataTypeClass = ContractDTO.class),
            @ApiImplicitParam(name = "files", value = "files", paramType = "form", dataType = "Object", dataTypeClass = MultipartFile.class),
            @ApiImplicitParam(name = "statuses", value = "statuses", paramType = "form", dataType = "Object", dataTypeClass = ContractStatusDTO.class),
    })
    @ResponseBody
    @RequestMapping(value = "/save", method = RequestMethod.POST, consumes = {"multipart/form-data"}, produces = {"application/json"})
    private Result<Object> test(@RequestPart(value = "contract", required = true) @NotNull ContractDTO contract,
                                @RequestPart(value = "files", required = false) List<MultipartFile> files,
                                @RequestPart(value = "statuses", required = false) List<ContractStatusDTO> statuses) throws Exception {
        if (null == contract) {
            return Result.errorWithMsg("合同不能为空");
        }
        ContractDTO currentContract = contractService.getOneByName(null == contract.getContractName() ? null : contract.getContractName());
        ObjectId sendContractId = contract.getContractId();
        if ( null == sendContractId ) {
            if (null != currentContract){
                return Result.errorWithMsg("合同已存在");
            }
            contract.setCreateTime(new Date());
            contract.setDeleted(DefaultValue.NOT_DELETED);
            contract.setContractId(new ObjectId());
            if (null != statuses && statuses.size() != 0){
                BigDecimal currentAmount = statuses.stream().map(ContractStatusDTO::getPayment).filter(Objects::nonNull).reduce(BigDecimal.ZERO,BigDecimal::add);
                contract.setCurrentAmount(currentAmount);
                statuses = statuses.stream().peek(e -> {
                    e.setContractId(contract.getContractId().toString());
                    e.setDeleted(DefaultValue.NOT_DELETED);
                }).collect(Collectors.toList());
                statusService.saveAll(statuses);
            }
            if (null != files && files.size() != 0) {
                List<AttachmentDTO> attachmentList = this.fileConvertToAttachmentDto(contract.getContractId().toString(),files);
                if (null == attachmentList){
                    return Result.errorWithMsg("文件上传出现问题");
                }
                attachmentService.saveAll(attachmentList);
            }
            ContractDTO resSave = contractService.save(contract);
            return Result.successWithMsgAndData("提交成功", resSave.getContractId().toString());
        } else {
            if (null == currentContract){
                return Result.errorWithMsg("合同不存在");
            }
            BeanUtil.copyProperties(contract,currentContract, CopyOptions.create().ignoreNullValue());
            ContractDTO resSave = contractService.save(currentContract);
            return Result.successWithMsgAndData("修改成功", resSave.getContractId().toString());
        }
    }




}
